package com.crazypos.common.utils;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.crazypos.config.JWTConfig;
import com.crazypos.constant.CommonConstant;
import com.crazypos.pojo.UserEntity;
import com.crazypos.security.entity.UserDetailEntity;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import sun.misc.BASE64Decoder;

import java.lang.reflect.Type;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

public class JWTTokenUtil {
    public static String createToken(UserDetailEntity userEntity, int expire) throws Exception {

        if (expire <= 0) {
            expire = JWTConfig.expiration;
        }

        // 计算超时时间
//        LocalDateTimeUtil.now().plusDays(expire);
//        ZonedDateTime zdt = LocalDate.now().plus(expire, ChronoUnit.DAYS).atStartOfDay(ZoneId.systemDefault());
//        Date expireDate = Date.from(zdt.toInstant());

        // 生成Token
        String token = Jwts.builder()
                // JWT ID 无实际意义
                .setId(UUID.randomUUID().toString())
                // PAYLOAD
                .claim(JWTConfig.userTokenKey, JSON.toJSONString(userEntity))
                .claim("authorities", JSON.toJSONString(userEntity.getAuthorities()))
                // 过期时间
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                // 签名
                .signWith(SignatureAlgorithm.RS256, getPrivateKey())
                .compact();

        return token;
    }

    public static Object parseUserInfoFromToken(String token, Type type) throws Exception {
        if (StringUtils.isEmpty(token)) {
            return null;
        }

        Jws<Claims> claimsJws = parseToken(token, getPublicKey());
        Claims body = claimsJws.getBody();

        // token过期
        if (body.getExpiration().before(Calendar.getInstance().getTime())) {
            return null;
        }

        return JSON.parseObject(
                body.get(JWTConfig.userTokenKey).toString(),
                type
        );

    }

    private static Jws<Claims> parseToken(String token, PublicKey publicKey) {
        return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
    }

    public static Jws<Claims> parseToken(String token) throws Exception {
        return parseToken(token, getPublicKey());
    }

    /**
     * 根据本次存储的公钥获取到 publickey 对象
     *
     * @return
     */
    private static PublicKey getPublicKey() throws Exception {
        X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(
                new BASE64Decoder().decodeBuffer(CommonConstant.PUBLIC_KEY)
        );
        return KeyFactory.getInstance("RSA").generatePublic(encodedKeySpec);
    }

    /**
     * 根据本地存储的私钥获取到 PrivateKey 对象
     *
     * @return
     * @throws Exception
     */
    private static PrivateKey getPrivateKey() throws Exception {
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(
                new BASE64Decoder().decodeBuffer(CommonConstant.PRIVATE_KRY)
        );

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(spec);
    }

}
